高速と噂される SQL リンターツール「sqruff」を実際に試してみた
Google Cloud データエンジニアのはんざわです。
皆さん、SQL のリンターを使っていますか?
過去のブログで SQL のリンターである sqlfluff を紹介しましたが、本ブログでは、sqlfluff よりも高速と噂される新しいツール「sqruff」を試してみたいと思います。
(余談ですが、この「sqruff」ってどう発音するんでしょうね、SQL + Ruff で「エスキューラフ」?それとも別の発音?)
検証環境
- OS とバージョン
- macOS 13.5.2
- パッケージ管理システム
- Homebrew 4.4.8
- SQL の方言
- BigQuery
sqruff とは?
sqruff は、Rust で開発された SQL リンターおよびフォーマッターのオープンソースツールです。
似たようなツールとして sqlfluff がありますが、sqruff はその sqlfluff よりも高速だと噂されています。
投稿日時点では、以下の SQL の方言に対応しています。将来的には、さらに多くの方言がサポートされる予定とのことです。
ANSI SQL(デフォルト)
BigQuery
Athena
Clickhouse
DuckDB
PostgreSQL
Snowflake
SparkSql
SQLite
Trino
ローカル環境で触ってみる
本ブログでは、ローカル環境で sqruff を実際に試してみます。
インストール
brew install
コマンドを使って sqruff をインストールします。以下のコマンドを実行します。
$ brew install quarylabs/quary/sqruff
インストール後、バージョンの確認を行い、正常にインストールされているか確認します。
$ sqruff --version
> sqruff 0.20.2
機能の概要
sqruff には、主に以下の 2 つの機能があります。
- lint:SQL を読み込み、事前に定義されたルールに沿って問題点を指摘します。
- fix:問題点を指摘するだけでなく、SQL クエリを修正します。
これらの動作は sqlfluff とほとんど同じため、すでに sqlfluff を使ったことがある方には馴染みやすいツールだと思います。
sqruff
コマンドの詳細については、以下のドキュメントを参考にしてください。
本ブログでは、lint
の機能を試してみます。
ルールファイルの作成
まずは、sqruff のルールファイルを作成します。
ルール設定は .sqruff
ファイルで行い、このファイルを sqruff
コマンドを実行するディレクトリに配置します。
sqlfluff を使ったことがある方は、sqruff のルールファイルが sqlfluff の .sqlfluff
ファイルと非常に似ているため、ほぼ同じ感覚で設定できると思います。
以下は、例として作成した .sqruff
ファイルです。この設定では、SQL 方言を BigQuery に指定し、AM01 と AM02 を除くすべてのルールを有効にしています。
[sqruff]
dialect = bigquery
rules = all
exclude_rules = AM01,AM02
[sqruff:indentation]
indent_unit = space
tab_space_size = 4
ルール名(例:AM01, AM02)や各ルールの詳細については、以下のドキュメントを参考にしてください。
また、ルールファイルで設定できる項目(例:dialect, rules など)の一覧については、以下のドキュメントを参考にしてください。
動かしてみる
次に、フォーマットが乱れているサンプルの SQL ファイルを用意します。
with temp AS (
SELECT *
FROM sample.test
)
selecT id,
hoge,
ifnull(fuga, '')
FROM
temp t
.sqruff
ファイルが配置されているディレクトリで、以下のコマンドを実行します。
$ sqruff lint sql/sample.sql
結果は以下の通りです。
== [sql/sample.sql] FAIL
L: 1 | P: 11 | CP01 | Keywords must be consistently lower case.
| [capitalisation.keywords]
L: 2 | P: 5 | CP01 | Keywords must be consistently lower case.
| [capitalisation.keywords]
L: 2 | P: 11 | LT01 | Expected only single space before "*". Found " ".
| [layout.spacing]
L: 3 | P: 5 | CP01 | Keywords must be consistently lower case.
| [capitalisation.keywords]
L: 6 | P: 1 | CP01 | Keywords must be consistently lower case.
| [capitalisation.keywords]
L: 6 | P: 1 | LT09 | Select targets should be on a new line unless there is
| only one select target.
| [layout.select_targets]
L: 6 | P: 7 | LT02 | Expected line break and indent of 4 spaces before "id".
| [layout.indent]
L: 7 | P: 1 | LT02 | Expected indent of 4 spaces
| [layout.indent]
L: 8 | P: 1 | LT02 | Line should not be indented.
| [layout.indent]
L: 8 | P: 3 | AL03 | Column expression without alias. Use explicit `AS`
| clause. [aliasing.expression]
L: 8 | P: 3 | CV02 | Use 'COALESCE' instead of 'IFNULL'.
| [convention.coalesce]
L: 9 | P: 1 | CP01 | Keywords must be consistently lower case.
| [capitalisation.keywords]
L: 10 | P: 1 | LT02 | Expected indent of 4 spaces.
| [layout.indent]
L: 10 | P: 8 | AL01 | Implicit/explicit aliasing of table.
| [aliasing.table]
L: 10 | P: 8 | AL05 | Alias 't' is never used in SELECT statement.
| [aliasing.unused]
The linter processed 1 file(s).
All Finished 📜 🎉
結果を見ると、ルール違反の箇所がリストアップされています。
L
は行番号、P
は文字位置を表しています。この例では、次のように修正することでインデントのチェックをパスできます。
with temp as (
select *
from
sample.test
)
select
t.id,
t.hoge,
coalesce(t.fuga, '') as fuga
from
temp as t
再度、lint
を実行すると、問題が解消されていることが確認できます。
$ sqruff lint sql/sample.sql
The linter processed 1 file(s).
All Finished 📜 🎉
このように、sqruff は sqlfluff と同じ感覚で簡単に利用できます。
おまけ:sqlfluff と速度を比較してみる
上記の公式ブログによると、sqruff は sqlfluff と比較して高速であると紹介されています。
実際にどれほどの差があるのか、行数の異なる SQL ファイルを用意して検証してみました。
検証の環境
検証に使用したバージョンは以下の通りです。
$ sqlfluff --version
> sqlfluff, version 3.2.5
$ sqruff --version
> sqruff 0.20.2
また、.sqlfluff
と .sqruff
のルールファイルは統一しています。
[sqlfluff]
dialect = bigquery
rules = all
[sqlfluff:indentation]
indent_unit = space
tab_space_size = 4
[sqruff]
dialect = bigquery
rules = all
[sqruff:indentation]
indent_unit = space
tab_space_size = 4
各リンターの速度は、以下のコマンドで計測しました。
それぞれのコマンドを 3 回ずつ実行し、速度を比較してみたいと思います。
# sqlfluff lint
start=$(gdate +%s.%N); sqlfluff lint sql/; end=$(gdate +%s.%N); echo "Execution time: $(printf "%.2f" $(echo "$end - $start" | bc)) seconds"
# sqruff lint
start=$(gdate +%s.%N); sqruff lint sql/; end=$(gdate +%s.%N); echo "Execution time: $(printf "%.2f" $(echo "$end - $start" | bc)) seconds"
検証の結果
- 行数小さいクエリ
まずは、行数が小さいクエリで試してみます。
行数が 25 で文字数が 636 のファイルを 10 個用意しました。
$ find ./short_sql -type f -exec wc -l -m {} +
25 636 ./short_sql/sample_5.sql
25 636 ./short_sql/sample_4.sql
25 636 ./short_sql/sample_6.sql
25 636 ./short_sql/sample_7.sql
25 636 ./short_sql/sample_3.sql
25 636 ./short_sql/sample_2.sql
25 636 ./short_sql/sample_1.sql
25 636 ./short_sql/sample_10.sql
25 636 ./short_sql/sample_9.sql
25 636 ./short_sql/sample_8.sql
250 6360 total
3 回実行した結果は以下の通りです。sqruff の方が sqlfluff と比べて約 10 倍高速であることが確認できました。
sqlfluff | sqruff | |
---|---|---|
1 回目 | 0.92 | 0.12 |
2 回目 | 0.92 | 0.10 |
3 回目 | 0.93 | 0.09 |
- 行数が大きいクエリ
次に、行数が大きいクエリで試してみます。
行数が 180 で文字数が 8460 のファイルを 10 個用意しました。
$ find ./long_sql -type f -exec wc -l -m {} +
180 8460 ./long_sql/sample_5.sql
180 8460 ./long_sql/sample_4.sql
180 8460 ./long_sql/sample_6.sql
180 8460 ./long_sql/sample_7.sql
180 8460 ./long_sql/sample_3.sql
180 8460 ./long_sql/sample_2.sql
180 8460 ./long_sql/sample_1.sql
180 8460 ./long_sql/sample_10.sql
180 8460 ./long_sql/sample_9.sql
180 8460 ./long_sql/sample_8.sql
1800 84600 total
3 回実行した結果は以下の通りです。行数が小さいクエリで見られたほどの差はなく、sqlfluff と sqruff の速度は比較的近い結果となりました。
sqlfluff | sqruff | |
---|---|---|
1 回目 | 4.21 | 3.55 |
2 回目 | 4.19 | 3.72 |
3 回目 | 4.30 | 3.70 |
考察
以下の Issue にも報告されているように、ファイルの行数が増えると sqruff のパフォーマンスが指数関数的に低下する現象が確認されています。さらに、SQL 方言が BigQuery の場合、他の方言よりもパフォーマンスが悪化する傾向があるようです。
プロジェクトによって SQL ファイルの行数や規模は異なると思いますが、今回の検証では以下のような特徴が確認できました。
- sqruff は、小さいクエリファイルを多数処理する場合に特に高速
- sqlfluff は、大規模なクエリファイルを安定して処理できる点が魅力
この検証結果は、ローカル環境で SQL の方言を BigQuery に設定した場合のものです。例えば、GitHub Actions(GHA)などの CI 環境や、他の SQL 方言を使用する場合には、異なる結果となる可能性があります。
これらの条件によってパフォーマンスがどう変化するかは、別途検証が必要です。
感想
今回のブログでは、sqruff を実際に触ってみました。
sqlfluff は、すでにある程度成熟したツールとして広く利用されているように思います。
一方で、sqruff はまだ発展途上のツールですが、その高速性は非常に魅力的で、これからさらに成長していく可能性があると感じています。
また、投稿日時点で dbt の方言はサポートされていませんが、上記の Issue にもある通り、今後対応していく動きもあります。これからのアップデートにも目が離せませんね。